# import requests
#
# url = "https://api.siliconflow.cn/v1/chat/completions"
#
# payload = {
#     "model": "deepseek-ai/DeepSeek-V3",
#     "messages": [
#         {
#             "role": "user",
#             "content": "What opportunities and challenges will the Chinese large model industry face in 2025?"
#         }
#     ],
#     "stream": False,
#     "max_tokens": 512,
#     "stop": None,
#     "temperature": 0.7,
#     "top_p": 0.7,
#     "top_k": 50,
#     "frequency_penalty": 0.5,
#     "n": 1,
#     "response_format": {"type": "text"},
#     "tools": [
#         {
#             "type": "function",
#             "function": {
#                 "description": "<string>",
#                 "name": "<string>",
#                 "parameters": {},
#                 "strict": False
#             }
#         }
#     ]
# }
# headers = {
#     "Authorization": "Bearer <token>",
#     "Content-Type": "application/json"
# }
#
# response = requests.request("POST", url, json=payload, headers=headers)
import os.path
import time
from collections import OrderedDict

# from openai import OpenAI
# system_prompt="""
# **定位**: 你是一位OCR文本修复专家，专注修正识别错误并保持原始结构。
#
# **处理规则**：
# 1. 仅输出修复后的最终文本
# 2. 自动修正：
#    - 错别字/断句/语义断层
# 3. 严格保留：
#    - 原始段落/换行/分页
#    - 表格框架（管道符排版）
#    - 公式（LaTeX）/代码块（带语法标识）
#    - 特殊符号&页码
# 4. 模糊内容根据上下文推断补全
#
# **输出要求**：
# - 维持原始文本的Markdown格式
# - 公式保留LaTeX格式
# - 表格保持管道符排版
# - 代码块保留语法标识
# """
# prompt="""
# ---## ## #Page 5
# .28 。         黑龙江大学工程 学报         第8 卷
# "Fae we okt 严 | 多
# s(t 重 | as
# we WE! 破
# OR DR |
# 4    ris               —
# | eo
# < aa
# =    Ae  —————=
# 1     — a,        CSl=1°
# 1    1                     CS2-4 |
#      19S2GS3 。 GS4             C8420"
# 014? 10” 20。 30     40 50     60
# 偏转角67(o)                                  (a)O=1.06° (b)O=4.00° — (c)@=9.93° —— (d)0-20.38。
# AS 性能目标划分                                     图6 各临界状态对应的损伤程度
# Fig.S Division of performance targets                        Fig.6 Degree of damage at each critical state
# 表3 SMRKATHE
# Table 3 Calculating values at each critical state
# 临界状态                        CS1                 CS2                 CS3                 CS4
# 偏转角 O 中位值 /(?)                     0. 833                 4. 156                 9. 645                  21. 686
# 偏转角 O 变异系数                         0. 172                   0. 235                    0.312                    0. 355
# 表4 5S00 kV 进线构架的性能目标
# Table 4 Performance targets of 500 kV substation frames
# 性能水准              完好              轻微破坏            中等破坏            严重破坏              倒塌
# 偏转角 0 /( ?)          <1.0           1.0~4.0         4.0 ~10.0        10. 0 ~20.0          >20.0
# 4 ，进线构架的性能目标
# 地震易损性是指结构在某一给定危险性水平的地震作用下地震需求 D 达到或超过结构抗力 C 的条件
# 概率 ，是结构的本身属性 。其中结构地震需求和抗力均服从对数正态分布，基于地震动强度的地震易
# 损性函数” :
# P, = P(D = C1 IM = im) = dg( co )              (1)
# O¢
# 式中Ac 为以地震动参数表示的结构抗力的中位值; ce 为以地震动参数表示的结构抗力对数标准差。
# 其中ec 和ec 可以通过式(2) 和式(3) 确定:
# Mo
# fic = -一一                                (2)
# J/1 + d&
# Oc = /In(1 + 8)                          (3)
# 式中 me 为不同临界状态下的能力平均值; 56c 为不同临界状态下的能力变异系数。
# 基于上节定义的500 kV 进线构架性能目标和各临界状态的建议取值, 选取40 AR EI LEARY
# 地震记录，场地类别属于下类场地。采用 IDA 方法获得结构性能目标所对应每一条记录的地震动强度，
# 采用式(2) 和式( 3) 进行统计分析，获得结构基于地震动强度的地震抗力统计值见表 5。
# """
#
# client = OpenAI(api_key="sk-khpelacohlqmoxrsotvikmfaevmmcbnaarkljxlqctlvccgp", base_url="https://api.siliconflow.cn/v1")
# response = client.chat.completions.create(
#     model="Qwen/Qwen2.5-14B-Instruct",
#     messages=[
#         {"role": "system", "content": system_prompt},
#         {"role": "user", "content": prompt}
#     ],
#     temperature=0.7,
#     max_tokens=4096,
#     top_p=0.7,
#     presence_penalty=0,
#     stream=False,
#     # response_format={"type": "json_object"}
# )
# message = response.choices[0].message
# content = message.content
# content = content.replace("\\n", "\n")  # 换行符
# content = content.replace("\\t", "\t")  # 制表符
# content = content.replace("\\\\", "\\")  # 反斜杠
# content = content.replace("\\\"", "\"")  # 双引号
# content = content.replace("\\'", "'")  # 单引号
# print(content)

from openai import OpenAI
from concurrent.futures import ThreadPoolExecutor
from typing import List, Dict, Tuple

from picture_to_text.utils import read_file_by_page, generate_file_pairs


class LLMChat:
    """大模型对话类，用于与LLM进行交互"""

    def __init__(
            self,
            api_key,
            base_url,
            model="Qwen/Qwen2.5-14B-Instruct",
            system_prompt="你是数据分析专家，用Markdown输出结果",
    ):
        """
        初始化LLMChat实例

        Args:
            api_key (str): API密钥
            base_url (str): API基础URL
            model (str, optional): 使用的模型名称，默认为"Qwen/Qwen2.5-14B-Instruct"
            system_prompt (str, optional): 系统提示词，默认为"你是数据分析专家，用Markdown输出结果"
        """
        # 初始化OpenAI客户端
        self.client = OpenAI(api_key=api_key, base_url=base_url)
        # 初始化属性
        self._model = model
        self._system_prompt = system_prompt
        self._temperature = 0.7
        self._max_tokens = 4096
        self._top_p = 0.7
        self._presence_penalty = 0
        self._stream = False
        self._concurrent_chat_limit = 4
        # self._response_format = {"type": "json_object"}

    @property
    def concurrent_chat_limit(self):
        """获取并发chat的最大数量"""
        return self._concurrent_chat_limit

    @concurrent_chat_limit.setter
    def concurrent_chat_limit(self, value):
        """设置并发chat的最大数量

        Args:
            value (int): 新的并发chat最大数量
        """
        self._concurrent_chat_limit = value

    @property
    def model(self):
        """获取当前使用的模型名称"""
        return self._model

    @model.setter
    def model(self, value):
        """设置模型名称

        Args:
            value (str): 新的模型名称
        """
        self._model = value

    @property
    def system_prompt(self):
        """获取系统提示词"""
        return self._system_prompt

    @system_prompt.setter
    def system_prompt(self, value):
        """设置系统提示词

        Args:
            value (str): 新的系统提示词
        """
        self._system_prompt = value

    @property
    def temperature(self):
        """获取生成文本的随机性参数，值越大输出越随机"""
        return self._temperature

    @temperature.setter
    def temperature(self, value):
        """设置生成文本的随机性参数

        Args:
            value (float): 新的温度值，范围通常为0.0到1.0
        """
        self._temperature = value

    @property
    def max_tokens(self):
        """获取最大token数限制"""
        return self._max_tokens

    @max_tokens.setter
    def max_tokens(self, value):
        """设置最大token数

        Args:
            value (int): 新的最大token数
        """
        self._max_tokens = value

    @property
    def top_p(self):
        """获取核采样参数，用于控制生成文本的多样性"""
        return self._top_p

    @top_p.setter
    def top_p(self, value):
        """设置核采样参数

        Args:
            value (float): 新的top_p值，范围通常为0.0到1.0
        """
        self._top_p = value

    @property
    def presence_penalty(self):
        """获取存在惩罚参数，用于控制重复内容的生成"""
        return self._presence_penalty

    @presence_penalty.setter
    def presence_penalty(self, value):
        """设置存在惩罚参数

        Args:
            value (float): 新的存在惩罚值
        """
        self._presence_penalty = value

    @property
    def stream(self):
        """获取是否使用流式响应的设置"""
        return self._stream

    @stream.setter
    def stream(self, value):
        """设置是否使用流式响应

        Args:
            value (bool): 是否启用流式响应
        """
        self._stream = value

    def chat(self, user_content):
        """
        与LLM进行对话

        Args:
            user_content (str): 用户输入内容

        Returns:
            str: 处理后的LLM响应内容
        """
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "system", "content": self.system_prompt},
                {"role": "user", "content": user_content},
            ],
            temperature=self.temperature,
            max_tokens=self.max_tokens,
            top_p=self.top_p,
            presence_penalty=self.presence_penalty,
            stream=self.stream
        )
        message = response.choices[0].message
        content = message.content
        # 处理特殊字符
        content = content.replace("\\n", "\n")  # 换行符
        content = content.replace("\\t", "\t")  # 制表符
        content = content.replace("\\\\", "\\")  # 反斜杠
        content = content.replace('\\"', '"')  # 双引号
        content = content.replace("\\'", "'")  # 单引号
        return content

    def chat_concurrent(self, user_contents):
        """
        并发执行多个chat请求

        Args:
            user_contents (list[str]): 用户输入内容列表

        Returns:
            list[str]: 按顺序返回处理后的LLM响应内容
        """
        with ThreadPoolExecutor(max_workers=self.concurrent_chat_limit) as executor:
            # 使用线程池并发执行chat方法
            futures = [executor.submit(self.chat, content) for content in user_contents]
            # 按顺序获取结果
            results = [future.result() for future in futures]
        return results


class LLMChatManager:
    """管理多个LLMChat对象的类，提供并发执行聊天请求的功能，并实现负载均衡"""

    def __init__(self):
        """初始化LLMChatManager实例"""
        self.llm_chats = []
        self.call_counts = {}  # 记录每个LLMChat对象的调用次数

    def add_llm_chat(self, llm_chat: LLMChat):
        """
        添加一个LLMChat对象到管理器中

        Args:
            llm_chat (LLMChat): 要添加的LLMChat对象
        """
        self.llm_chats.append(llm_chat)
        self.call_counts[id(llm_chat)] = 0  # 初始化调用次数为0

    def _get_task_allocation(self, user_contents: List[str]):
        """
        根据轮询方式分配任务，确保每个LLMChat对象都能被分配到任务，并记录原始索引。

        Args:
            user_contents (List[str]): 用户输入内容列表

        Returns:
            Tuple[List[List[str]], List[int]]: 分配的任务列表和对应的原始索引列表
        """
        allocated_tasks = [[] for _ in range(len(self.llm_chats))]
        original_indices = [[] for _ in range(len(self.llm_chats))]
        for i, content in enumerate(user_contents):
            idx = i % len(self.llm_chats)
            allocated_tasks[idx].append(content)
            original_indices[idx].append(i)
        return allocated_tasks, original_indices

    def chat_concurrent(self, user_contents: List[str]) -> List[str]:
        """
        并发执行多个chat请求，使用所有LLMChat对象的chat_concurrent方法，并根据concurrent_chat_limit分配任务。
        返回的结果与user_contents的原始顺序一致。

        Args:
            user_contents (List[str]): 用户输入内容列表

        Returns:
            List[str]: 按原始顺序返回处理后的LLM响应内容
        """
        allocated_tasks, original_indices = self._get_task_allocation(user_contents)
        # 根据调用次数动态分配任务
        sorted_llm_chats = sorted(self.llm_chats, key=lambda x: self.call_counts[id(x)])
        results = [None] * len(user_contents)  # 预分配结果列表
        with ThreadPoolExecutor(max_workers=len(self.llm_chats)) as executor:
            # 使用线程池并发执行每个LLMChat的chat_concurrent方法
            futures = [
                executor.submit(llm_chat.chat_concurrent, tasks)
                for llm_chat, tasks in zip(sorted_llm_chats, allocated_tasks)
            ]
            # 按顺序获取结果并填充到正确的位置
            for future, indices in zip(futures, original_indices):
                task_results = future.result()
                for result, idx in zip(task_results, indices):
                    results[idx] = result
            # 更新调用次数
            for llm_chat, tasks in zip(sorted_llm_chats, allocated_tasks):
                self.call_counts[id(llm_chat)] += len(tasks)
        return results

    def get_call_counts(self) -> Dict[str, int]:
        """
        获取每个LLMChat对象的调用次数

        Returns:
            Dict[str, int]: 包含每个LLMChat对象ID和调用次数的字典
        """
        return {str(id(llm_chat)): count for llm_chat, count in self.call_counts.items()}

    def get_concurrent_performance_info(self) -> Dict:
        """
        获取当前并发性能信息，包括总的并发限制和当前并发任务数

        Returns:
            Dict: 包含当前并发性能信息的字典
        """
        total_concurrent_limit = sum(llm_chat.concurrent_chat_limit for llm_chat in self.llm_chats)
        total_current_tasks = total_concurrent_limit  # 假设当前并发任务数为并发限制
        performance_info = {
            'total_concurrent_limit': total_concurrent_limit,
            'total_current_tasks': total_current_tasks,
            'llm_chats': [
                {
                    'concurrent_chat_limit': llm_chat.concurrent_chat_limit,
                    'current_concurrent_tasks': llm_chat.concurrent_chat_limit,  # 假设当前并发任务数为并发限制
                    'call_count': self.call_counts[id(llm_chat)]  # 添加调用次数
                }
                for llm_chat in self.llm_chats
            ]
        }
        return performance_info


def ocr_llm_repair(source_file_path, target_file_path, llm_chat_manager: LLMChatManager, page_break,
                   pages_per_batch=10):
    """
    对源文件进行OCR修复，并将结果保存到目标文件中。支持分批次处理长文件。

    Args:
        source_file_path (str): 源文件路径
        target_file_path (str): 目标文件路径
        llm_chat_manager (LLMChatManager): LLMChatManager实例，用于并发处理
        page_break (str): 分页分隔符
        pages_per_batch (int, optional): 每次处理的页数，默认为10
    """
    page_texts = []
    mod = "w"
    index = 0
    for i, page_text in enumerate(read_file_by_page(source_file_path, page_separator=page_break)):
        page_texts.append(page_text)
        # 当累积的页数达到pages_per_batch时，进行批量处理
        if len(page_texts) >= pages_per_batch:
            results = llm_chat_manager.chat_concurrent(page_texts)
            # 将处理结果写入目标文件
            with open(target_file_path, mod, encoding='utf-8') as target_file:
                for result in results:
                    target_file.write(result + '\n')
            mod = "a"
            # 清空page_texts，准备处理下一批
            page_texts = []
            print(f"Processed {i + 1} pages.")
        index = i
    # 处理剩余的页数（不足pages_per_batch的部分）
    if page_texts:
        results = llm_chat_manager.chat_concurrent(page_texts)
        with open(target_file_path, mod, encoding='utf-8') as target_file:
            for result in results:
                target_file.write(result + '\n')
        print(f"Processed {index + 1} pages.")


def batch_ocr_llm_repair(source_dir, target_dir, page_break, file_prefix=".md", pages_per_batch=10):
    """
    批量处理OCR文本，并使用LLM（大语言模型）进行修复，将结果写入目标目录中的文件。

    参数:
    - source_dir (str): 源文件目录，包含需要处理的OCR文本文件。
    - target_dir (str): 目标文件目录，用于存储修复后的文本文件。
    - page_break (str): 用于分隔页面的字符串标识符。
    - file_prefix (str): 文件前缀，默认为".md"，用于生成目标文件名。
    - pages_per_batch (int): 每批处理的页面数量，默认为10。

    返回值:
    - 无返回值，处理结果直接写入目标文件。
    """

    def _write_results_to_file(file_path, results, mode):
        with open(file_path, mode, encoding='utf-8') as target_file:
            for result in results:
                target_file.write(result + '\n')

    time_0 = time.time()
    last_time = time_0
    total_page_num = 0
    file_page_texts = OrderedDict()  # 存储每个文件的页面文本
    target_file_paths = OrderedDict()  # 存储目标文件路径
    last_file = ""  # 记录上一个处理的文件
    # 遍历源目录和目标目录中的文件对
    for source_file_path, target_file_path in generate_file_pairs(source_dir, target_dir, file_prefix, file_prefix):
        # 逐页读取源文件内容
        for page_text in read_file_by_page(source_file_path, page_separator=page_break):
            file_page_texts.setdefault(source_file_path, [])
            target_file_paths.setdefault(target_file_path, None)
            file_page_texts[source_file_path].append(page_text)
            total_page_num += 1
            # 当累计页面数达到每批处理的上限时，调用LLM进行修复并写入文件
            if total_page_num >= pages_per_batch:
                results = llm_chat_manager.chat_concurrent(sum(file_page_texts.values(), []))
                current_index = 0
                for i, (key, value) in enumerate(file_page_texts.items()):
                    mod = "w" if key != last_file else "a"
                    _write_results_to_file(list(target_file_paths.keys())[i],
                                           results[current_index:current_index + len(value)], mod)
                    current_index += len(value)
                    last_file = key
                # 重置计数器并清空缓存
                total_page_num = 0
                source_names = '\n'.join([os.path.basename(key) for key in file_page_texts.keys()])
                target_names = '\n'.join([os.path.basename(key) for key in target_file_paths.keys()])
                print(
                    f"Processed {total_page_num} pages.of source files:\n{source_names}\nto target files:\n{target_names}")
                print(f"current time taken: {time.time() - last_time}s")
                print(f"total time taken: {time.time() - time_0}s")
                last_time = time.time()
                target_file_paths.clear()
                file_page_texts.clear()
    # 处理剩余的页面
    if file_page_texts:
        results = llm_chat_manager.chat_concurrent(sum(file_page_texts.values(), []))
        current_index = 0
        for i, (key, value) in enumerate(file_page_texts.items()):
            mod = "w" if key != last_file else "a"
            _write_results_to_file(list(target_file_paths.keys())[i], results[current_index:current_index + len(value)],
                                   mod)
            current_index += len(value)
            last_file = key
        source_names = '\n'.join([os.path.basename(key) for key in file_page_texts.keys()])
        target_names = '\n'.join([os.path.basename(key) for key in target_file_paths.keys()])
        print(
            f"Processed {total_page_num} pages.of source files:\n{source_names}\nto target files:\n{target_names}")
        print(f"current time taken: {time.time() - last_time}s")
        print(f"total time taken: {time.time() - time_0}s")



if __name__ == "__main__":
    # 示例用法
    base_url = "https://api.siliconflow.cn/v1"
    model = "Qwen/Qwen2.5-14B-Instruct"
    system_prompt = """
    **定位**: 你是一位OCR文本修复专家，专注修正识别错误并保持原始结构。
    **处理规则**：
    1. 仅输出修复后的最终文本
    2. 自动修正：
       - 错别字/断句/语义断层
    3. 严格保留：
       - 原始段落/换行/分页
       - 表格框架（管道符排版）
       - 公式（LaTeX）/代码块（带语法标识）
       - 特殊符号&页码
    4. 模糊内容根据上下文推断补全
    **输出要求**：
    - 维持原始文本的Markdown格式
    - 公式保留LaTeX格式
    - 表格保持管道符排版
    - 代码块保留语法标识
    """

    api_key1 = "sk-khpelacohlqmoxrsotvikmfaevm"
    llm_chat1 = LLMChat(api_key1, base_url, model, system_prompt)
    llm_chat1.concurrent_chat_limit = 8

    api_key2 = "sk-ltvjuqigovpxkoizqpljlmbxgvx"
    llm_chat2 = LLMChat(api_key2, base_url, model, system_prompt)
    llm_chat2.concurrent_chat_limit = 8

    llm_chat_manager = LLMChatManager()
    llm_chat_manager.add_llm_chat(llm_chat1)
    llm_chat_manager.add_llm_chat(llm_chat2)

    # source_file_path = r"G:\works\books\abaqus_md\analysys_books\有限元分析及应用-曾攀.md"
    # target_file_path = r"\works\books\abaqus_md\analysys_books\test_result.md"
    #
    # ocr_llm_repair(source_file_path, target_file_path, llm_chat_manager, page_break="## ## #Page", pages_per_batch=16)

    source_dir = r"G:\works\books\abaqus_md"
    target_dir = r"G:\works\books\abaqus_llm_repair"
    batch_ocr_llm_repair(source_dir, target_dir, page_break="## ## #Page", pages_per_batch=32)

#     prompt = """
# ---## ## #Page 5
# .28 。         黑龙江大学工程 学报         第8 卷
# "Fae we okt 严 | 多
# s(t 重 | as
# we WE! 破
# OR DR |
# 4    ris               —
# | eo
# < aa
# =    Ae  —————=
# 1     — a,        CSl=1°
# 1    1                     CS2-4 |
#      19S2GS3 。 GS4             C8420"
# 014? 10” 20。 30     40 50     60
# 偏转角67(o)                                  (a)O=1.06° (b)O=4.00° — (c)@=9.93° —— (d)0-20.38。
# AS 性能目标划分                                     图6 各临界状态对应的损伤程度
# Fig.S Division of performance targets                        Fig.6 Degree of damage at each critical state
# 表3 SMRKATHE
# Table 3 Calculating values at each critical state
# 临界状态                        CS1                 CS2                 CS3                 CS4
# 偏转角 O 中位值 /(?)                     0. 833                 4. 156                 9. 645                  21. 686
# 偏转角 O 变异系数                         0. 172                   0. 235                    0.312                    0. 355
# 表4 5S00 kV 进线构架的性能目标
# Table 4 Performance targets of 500 kV substation frames
# 性能水准              完好              轻微破坏            中等破坏            严重破坏              倒塌
# 偏转角 0 /( ?)          <1.0           1.0~4.0         4.0 ~10.0        10. 0 ~20.0          >20.0
# 4 ，进线构架的性能目标
# 地震易损性是指结构在某一给定危险性水平的地震作用下地震需求 D 达到或超过结构抗力 C 的条件
# 概率 ，是结构的本身属性 。其中结构地震需求和抗力均服从对数正态分布，基于地震动强度的地震易
# 损性函数” :
# P, = P(D = C1 IM = im) = dg( co )              (1)
# O¢
# 式中Ac 为以地震动参数表示的结构抗力的中位值; ce 为以地震动参数表示的结构抗力对数标准差。
# 其中ec 和ec 可以通过式(2) 和式(3) 确定:
# Mo
# fic = -一一                                (2)
# J/1 + d&
# Oc = /In(1 + 8)                          (3)
# 式中 me 为不同临界状态下的能力平均值; 56c 为不同临界状态下的能力变异系数。
# 基于上节定义的500 kV 进线构架性能目标和各临界状态的建议取值, 选取40 AR EI LEARY
# 地震记录，场地类别属于下类场地。采用 IDA 方法获得结构性能目标所对应每一条记录的地震动强度，
# 采用式(2) 和式( 3) 进行统计分析，获得结构基于地震动强度的地震抗力统计值见表 5。
# """
#     prompt1 = prompt
#     prompt2 = """
# ---## ## #Page 43
# 2.4 ABAQUS/CAE 模块 (Modules) 功能简介               31
#
# 一一一一”~ CeS 功能人人 3
# 元软件不同，   不能直接将材料特性赋予相应的单元和几何部件，   而是必须先将材料特性定
# 义在截面属性 (section) 上， 再将截面属性赋予相应的部件或部件的某些区域上。 此处的
# 截面属性指的是广义的截面属性，包括梁的截面形状。 在 ABAQUS 中定义材料特性一般
# 分为三个基本步骤: 定义材料的本构模型、 定义截面属性、将截面属性赋予部件的不同区
# 域，这些具体操做已经在实例 2-1 中具体讲解。 在 Property 模块中，用户可以定义和编辑
# 材料 (materials) 、梁截面形状 (profile) 和截面属性 (sections), 梁截面 (beam sec-
# tion) 通过梁截面形状〈profile) 来定义。下面简单介绍 Property 模块的具体功能、
#
# 1. 定义材料: 在菜单 Material 选项中可以选择 Create 子菜单定义有关材料的所有特
# 性数据，例如弹性模量、泊松比、密度、 抗压屈服强度等参数。也可以通过 Edit 对每种
# 材料的本构关系进行修改。
#
# ABAQUS 在材料定义中提供了许多材料的本构模型和失效破坏准则， 主要包括弹性
# 材料模型、塑性材料模型和其他材料模型，如图 2-53 《oa)、(2) 所示，用户可以根据自己
# 的需要选择合适的模型。
#
# eee | eee ced
#
# eed
#
# | SESS Be | SEER See
# |           = Po = |      ee |     |
# |
# SE eee           Meee   © = WMRERN ie 0 Gaps
# (a)                               (b)
# 图 2-53 ”材料本构模型
# 六小贴士: ABAQUS 提供了大量的与土木有关的本构模型， 包括线弹性模型、混凝土损
# 伤模型、混凝土弥散模型、扩展 Dr-P 模型等，用户还可以通过 ABAQUS 提供
# 的自定义材料模型的子程序 UMAT 来定义自己需要的本构模型，
#
# 2. 定义梁截面形状;，梁单元的材料是通过梁截面属性定义的， 梁截面属性的指定与
# 梁横截面的形状和尺寸有关，因此在对梁单元材料定义时， 就需要使用梁截面形状〈Pro-
# file), ABAQUS 提供两种梁截面选择方式: 一是基本梁截面形状， 包括任意形状 〈arbi-
# trary) 、箱形 (box), PK (circular), AVE (Chexagonal) 、和矩形 〈rectangular) 、梯形
# (trapezoidal), IB (pipe), 1B. LMT IH; 二是广义梁形状〈Generalized profiles) 。
# 用户可以根据自己的模型，选择合适的类型。
#
# WINE: 用户在定义梁截面形状时，必须要定义梁截面方位〈〔beam orientation) ，否则
# """
#     prompt3 = """
# ---## ## #Page 86
# _ 7I4               _ 3% ABAQUS 在钢结构中的应用        —
#
# MB Edit Section Assignaent       ed   有参数默认值不变， 点击 OK， 部件中柱由 A
# Section                SEE    色变成青色，完成对柱赋予截面属性的操作。
# Section  Section-1  sm    -  (Create })       点击左侧工具区 的 Efe.  在绘 图区选
# 了 择模 型 中所有的 梁 ，点击 鼠标中键确认，弹
# Type:   Bows                  |   出 Edit Section Assignment 对话框，Section
# Materiel: ‘steel                     由后选择 Section-2，保持所有参数默认值不变，
# Region             二| 点击OK，部件中梁由白色变成青色，完成对
# Region: Picked) (Edit Region} |] 滁赋子截面属性的操作。
#
# (ox        (Cancer }          5. 给部件赋予梁截面方向
# 选择主菜单 Assign Beam Section (小
# 图 3-24 Edit Section Assignment 对话框  rientation  (梁截面方向) ，或点击左侧工具区
# 的宝，进行梁截面方向的设定。提示区显示
# “Select the regions to be assigned a beam section orientation” (选择要指定梁截面方向的
# 区域) ，选中整个部件，点击鼠标中键确认，如图 3-25 所示。提示区显示“Enter an ap-
# proximate nl direction (tangent vectors are shown)” (输入一个合适的 nl 方向，切矢量
# 默认显示)，保持所有参数默认值不变,，点击鼠标中键确认，完成对部件梁截面方向的定
# 义，如图 3-26 所示。
# 4    rt    a    4    4    4    r
# a ; 加 ; 的  ba | a  ry | >
# «1      « l      A        «-
# A    rt    4    r    4    人    人
# 一-中    a | le    Be   ~    md | -上
# a        A        rN        A
# «+      «—t      “        «I
# 4    cS    A    a    4    A    A
# a ae      <一      «        «A
# mer        r        人        A
# 图 3-25 YEAR ITTY Ia ESL                        图 3-26”梁截面方向
# SoM: 在使用梁截面形状创建梁截面特性时，必须指定梁截面方向，具体介绍见
# 2.4.2节。
# 3.2.5 定义装配件
# 在环境栏的 Module 列表中选择 Assembly (装配)  功能模块。
# 点击左侧工具区的曾按钮，绘图区显现钢梁三维模型，同时弹出 Create Instance 对话
# 框，如图 3-27 所示。默认 Instance Type 为 Dependent (非独立)，  点击 OK，退出 Create
# Instance 对话杠，完成装配件的定义。
#
# """
#     prompt4 = """
# ---## ## #Page 121
# i ee 09
# 图 3-152 ”节点变形后的网格模型          图 3-153 ”节点 Mises 应力云纹图
# 3. 绘制加载点的滞回曲线
# 点击左侧工具区中的固 按钮，在弹出的 Create XY Data 对话框中选择 ODB Field
# output, ii Continue，弹出 XY Data from ODB Field output 对话框，如图 3-154 所
# 示，在 Position 项中选择 Unique Nodal ，点击 RF: Reaction force 旁边的三角形，选中
# RF3，点击 U: Spatial displacement 4714 MY  :角形，选中 U3，点击此对话框中的 Ele-
# ments/Nodes 标签，进入 Elements/Nodes 标签页 ，点 击 Edit Selection，下拉菜单提示
# 用户在绘图区中选择测试点，点击鼠标左键选择型钢梁加载点，再点击鼠标中键确认，
# 点击 Plot 按钮，视图区中就显示加载点处节点力、位移随时间变化的曲线，如图 3
# 155 所示。
# M8 XY Data from ODB Field Output                              pal
# Steps/Frames
# Note: XY Data will be extracted from the active steps/ frames
# Variables Elements/Nodes
# Output Variables
# Position: Unique Nodal    ¥
# Click checkboxes or edit the identifiers shown next to Edit below
# 日zzz
# 回了3
# > Cis Stress components
# v fu Spatial displacement
# [(_] Magni tude
# ou
# (ve
# (us                                                   v
# Edit: | RF. RF3, U. U3
# Section point
# Save                   Plot                  Dismiss
# 图 3-154 XY Data from ODB Field output 对 话框
#
# """
#
#
#     print(llm_chat_manager.get_concurrent_performance_info())
#     time_0 = time.time()
#     chat_results = llm_chat_manager.chat_concurrent([prompt1, prompt2, prompt3, prompt4])
#     print(f"Concurrent chat time: {time.time() - time_0}")
#     print(llm_chat_manager.get_call_counts())
#
#     # print(llm_chat.chat(prompt))
#     # chat_results = llm_chat.chat_concurrent([prompt1, prompt2, prompt3, prompt4])
#     for i in chat_results:
#         print(i)
